package com.wind.taobao.core.webservice
{
	import com.wind.taobao.core.config.TaobaoConfig;
	import com.wind.taobao.core.exception.InvalidRequestParametersException;
	import com.wind.taobao.core.util.TaobaoConstants;
	import com.wind.taobao.core.webservice.event.TaobaoSenderEvent;

	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLVariables;

	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.http.mxml.HTTPService;
	import mx.utils.ObjectUtil;

	[Event(name="successful", type="com.wind.taobao.core.webservice.event.TaobaoSenderEvent")]
	[Event(name="ioError", type="flash.events.IOErrorEvent")]
	[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
	/**
	 * 淘宝远程服务类
	 * @author fxy
	 */
	public class TaobaoSender extends EventDispatcher
	{
		/**
		 * 请求URL
		 */
		[Bindable]
		public var url:String;
		/**
		 * 代理地址
		 */
		[Bindable]
		public var proxyUrl:String;
		/**
		 * 请求开始计时
		 */
		private var start:Number;
		/**
		 * 参数
		 */
		[Bindable]
		public var parameters:TaobaoRequest;
		/**
		 * 是否校验参数
		 */
		[Bindable]
		public var validate:Boolean=false;
		/**
		 * 提交方式
		 */
		[Bindable]
		public var method:String="post";

		public function TaobaoSender()
		{
		}

		/**
		 * 请求XML
		 * @param parameters
		 *
		 */
		public function restXML(parameters:TaobaoRequest=null):void
		{
			if (parameters != null)
			{
				this.parameters=parameters;
			}
			parameters.format="xml";
			rest(parameters);
		}

		/**
		 * 请求JSON
		 * @param parameters
		 *
		 */
		public function restJSON(parameters:TaobaoRequest=null):void
		{
			if (parameters != null)
			{
				this.parameters=parameters;
			}
			parameters.format="json";
			rest(parameters);
		}

		/**
		 * REST请求。默认JSON
		 * @param parameters
		 *
		 */
		public function rest(parameters:TaobaoRequest=null):void
		{
			//获取属性数组
			var claInfo:Object=ObjectUtil.getClassInfo(parameters);
			var props:Array=claInfo["properties"];
			if (!this.url)
			{
				if (parameters.isSandbox) //如果是请求沙箱环境
				{
					this.url=TaobaoConfig.sandboxUrl;
				}
				else
				{
					this.url=TaobaoConfig.url;
				}
			}
			Debug.log(this.url + ":" + parameters.isSandbox);
			if (validate) //是否校验参数
			{
				try
				{
					parameters.validate(); //请求参数校验
				}
				catch (error:InvalidRequestParametersException)
				{
					Alert.show(error.message);
					return;
				}
			}
			var params:ArrayCollection=parameters.getParameters(props, validate);
			var variables:Object=new Object();
			if (params && params.length > 0)
			{
				for each (var obj:Object in params)
				{
					variables[obj.key]=obj.value;
					Debug.log(obj.key + ":" + obj.value, Debug.PINK);
				}
			}
			sendHttpService(variables);
			//sendHttp(params, parameters.format == "json" ? "json" : "xml");
			//TODO 文件类API请求
//			if (parameters is TaobaoFileRequest && TaobaoFileRequest(parameters).getFileReference()) //
//			{
//				sendFileReference(obj, TaobaoFileRequest(parameters));
//			}
//			else //非文件类API请求
//			{
//				sendHttpService(obj);
//			}
		}

		private function sendHttp(param:ArrayCollection, format:String="json"):void
		{
			var loader:URLLoader=new URLLoader();
			var urlRequest:URLRequest=new URLRequest();
			urlRequest.url=(this.proxyUrl ? (this.proxyUrl + "?proxyURL=" + this.url) : this.url);
			urlRequest.method=this.method;
			loader.dataFormat=format;
			var variables:URLVariables=new URLVariables();
			if (param && param.length > 0)
			{
				for each (var obj:Object in param)
				{
					variables[obj.key]=obj.value;
				}
			}
			urlRequest.data=variables;
			if (format == "xml")
			{
				loader.addEventListener(Event.COMPLETE, sendXMLComplete);
			}
			else
			{
				loader.addEventListener(Event.COMPLETE, sendJSONComplete);
			}
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, sendSecurity);
			loader.addEventListener(IOErrorEvent.IO_ERROR, sendFailed);
			loader.load(urlRequest);
		}

		private function sendXMLComplete(event:Event):void
		{
			handleXML(new XML(URLLoader(event.target).data));
		}

		private function sendJSONComplete(event:Event):void
		{
			handleJSON(URLLoader(event.target).data);
		}

		private function sendSecurity(event:SecurityErrorEvent):void
		{
			this.dispatchEvent(event);
		}

		private function sendFailed(event:IOErrorEvent):void
		{
			this.dispatchEvent(event);
		}

		private function sendFileReference(obj:Object, parameters:TaobaoFileRequest):void
		{
			var fileReference:FileReference=parameters.getFileReference();
			if (fileReference != null)
			{
				var urlRequest:URLRequest=new URLRequest();
				urlRequest.url=this.url;
				urlRequest.method=this.method;
				urlRequest.data=obj;
				if (obj["format"] == "xml")
				{
					fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, handleXMLUploadComplete);
					fileReference.addEventListener(IOErrorEvent.IO_ERROR, handleSendError);
				}
				else
				{
					fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, handleJSONUploadComplete);
					fileReference.addEventListener(IOErrorEvent.IO_ERROR, handleSendError);
				}
				fileReference.upload(urlRequest, "image");
			}
		}

		/**
		 * 文件类JSON请求成功
		 * @param event
		 *
		 */
		private function handleJSONUploadComplete(event:DataEvent):void
		{
			handleJSON(event.data as String);
		}

		/**
		 * 文件类XML请求成功
		 * @param event
		 *
		 */
		private function handleXMLUploadComplete(event:DataEvent):void
		{
			handleXML(event.data as XML);
		}

		/**
		 * 非文件请求
		 * @param obj
		 *
		 */
		private function sendHttpService(obj:Object):void
		{
			var http:HTTPService=new HTTPService();
			http.method=this.method;
			http.resultFormat=(obj["format"] == "xml" ? "e4x" : "text");
			http.url=(this.proxyUrl ? (this.proxyUrl + "?proxyURL=" + this.url) : this.url);

			if (obj["format"] == "xml")
			{
				http.addEventListener(ResultEvent.RESULT, handleSendXMLComplete);
				http.addEventListener(FaultEvent.FAULT, handleSendError);
			}
			else
			{
				http.addEventListener(ResultEvent.RESULT, handleSendJSONComplete);
				http.addEventListener(FaultEvent.FAULT, handleSendError);
			}
			try
			{
				start=new Date().getTime();
				http.send(obj);
			}
			catch (error:Error)
			{
				throw new Error(error);
			}
		}

		/**
		 * 请求JSON成功
		 * @param event
		 *
		 */
		private function handleSendJSONComplete(event:ResultEvent):void
		{
			handleJSON(event.result as String);
		}


		/**
		 * 请求XML成功
		 * @param event
		 *
		 */
		private function handleSendXMLComplete(event:ResultEvent):void
		{
			handleXML(event.result as XML);
		}


		private function handleSendError(event:FaultEvent):void
		{
			dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false, event.message ? event.message.toString() : ""));
		}

		/**
		 * 解析返回值为XML
		 * @param xml
		 *
		 */
		private function handleXML(xml:XML):void
		{
			var response:TaobaoResponse=new TaobaoResponse();
			response.format="xml";
			response.body=xml;
			if (xml.(hasOwnProperty(TaobaoConstants.ERROR_RSP)))
			{
				response.errorCode=xml.error_rsp.code;
				response.msg=xml.error_rsp.msg;
			}
			Debug.log("当前请求耗时:" + (new Date().getTime() - start), Debug.PINK);
			this.dispatchEvent(new TaobaoSenderEvent(TaobaoSenderEvent.SUCCESSFUL, response));
		}

		/**
		 * 解析返回值为JSON
		 * @param json
		 *
		 */
		private function handleJSON(json:String):void
		{
			var response:TaobaoResponse=new TaobaoResponse();
			response.format="json";
			response.body=json;
			Debug.log("当前请求耗时:" + (new Date().getTime() - start), Debug.PINK);
			this.dispatchEvent(new TaobaoSenderEvent(TaobaoSenderEvent.SUCCESSFUL, response));
		}
	}
}